/**
 * JNI:(Java Native Interface:Java本地接口)
 *
 * JNI中本地函数的注册有两种：
 *      1.静态注册 通过包名+方法名建立关联
 *      2.动态注册 建立方法表，重写JNI_OnLoad()函数，然后注册映射关系
 */

#include <jni.h>
#include <string>
#include <unistd.h>

#include "LogUtil.h"
#include "UserAgent.h"
#include "JNIHelper.h"
#include "android/Convert_Device.h"

#define LOG_TAG "JNI"
#define JNI_VERSION JNI_VERSION_1_4

/**
 * 上层调用System.loadLibrary()加载库时，会首先搜索JNI_OnLoad()函数，如果存在则执行它，如果不存在，
 * 则会使用旧版本JNI，即1.1
 * 作用：1.告诉JVM，使用的JNI版本
 *      2.执行初始化操作
 *      3.将JavaVM参数保存为全局对象，方便以后在任何地方获取JNIEnv对象
 */
extern "C"
JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
  LOG_INFO("fun:%s", __FUNCTION__)
  JNIHelper::Instance()->setJavaVM(vm);
  auto env = JNIHelper::Instance()->getEnv(JNI_VERSION);
  if (!env) {
    return JNI_ERR;
  }

  return JNI_VERSION;
}

/**
 * 当GC回收这个库的ClassLoaders时，该函数被调用
 */
extern "C"
JNIEXPORT void JNI_OnUnload(JavaVM *vm, void *reserved) {
  LOG_INFO("fun:%s", __FUNCTION__)
  JNIHelper::Destroy();
  vm->DestroyJavaVM();
}

extern "C"
JNIEXPORT jboolean JNICALL
Java_com_fan_play_media_engine_MediaEngine_Create(JNIEnv *env, jobject thiz, jobject context) {
  LOG_INFO("fun:%s", __FUNCTION__)
  UserAgent::Instance();

  return true;
}

extern "C"
JNIEXPORT void JNICALL
Java_com_fan_play_media_engine_MediaEngine_Destroy(JNIEnv *env, jobject thiz) {
  LOG_INFO("fun:%s", __FUNCTION__)
  UserAgent::Destroy();
}
extern "C"
JNIEXPORT void JNICALL
Java_com_fan_play_media_engine_MediaEngine_SetCodecType(JNIEnv *env, jobject thiz,
                                                        jboolean soft_decode,
                                                        jboolean soft_encode) {
  LOG_INFO("fun:%s soft_decode:%s,soft_encode:%s", __FUNCTION__,
           Bool2Str(soft_decode), Bool2Str(soft_encode))
  UserAgent::Instance()->setCodecType(soft_decode, soft_encode);
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_fan_play_media_engine_MediaEngine_AddScreenDevice(JNIEnv *env, jobject thiz, jint width,
                                                           jint height) {
  LOG_INFO("fun:%s width:%d,height:%d", __FUNCTION__, width, height)
  return UserAgent::Instance()->addScreenDevice(width, height);
}

extern "C"
JNIEXPORT jboolean JNICALL
Java_com_fan_play_media_engine_MediaEngine_AddIPCameraDevice(JNIEnv *env, jobject thiz,
                                                             jstring stream_url,
                                                             jboolean soft_decode, jint dev_type) {
  auto stStream = env->GetStringUTFChars(stream_url, JNI_FALSE);
  LOG_INFO("fun:%s stream_url:%s,soft_decode:%d,dev_type:%d", __FUNCTION__, stStream, soft_decode,
           dev_type)
  jboolean ret = UserAgent::Instance()->addIPCameraDevice(stStream, soft_decode, dev_type);
  env->ReleaseStringUTFChars(stream_url, stStream);
  return ret;
}

extern "C"
JNIEXPORT void JNICALL
Java_com_fan_play_media_engine_MediaEngine_DeleteCaptureDevice(JNIEnv *env, jobject thiz,
                                                               jint dev_id) {
  LOG_INFO("fun:%s devID:%d", __FUNCTION__, dev_id)
  UserAgent::Instance()->deleteCaptureDevice(dev_id);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_fan_play_media_engine_MediaEngine_ClearCaptureDevice(JNIEnv *env, jobject thiz) {
  LOG_INFO("fun:%s", __FUNCTION__)
  UserAgent::Instance()->clearCaptureDevice();
}

extern "C"
JNIEXPORT void JNICALL
Java_com_fan_play_media_engine_MediaEngine_ModifyCameraDevice__II(JNIEnv *env, jobject thiz,
                                                                  jint width, jint height) {
  LOG_INFO("fun:%s width:%d,height:%d", __FUNCTION__, width, height)
  UserAgent::Instance()->modifyCameraDevice(width, height);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_fan_play_media_engine_MediaEngine_ModifyCameraDevice__III(JNIEnv *env, jobject thiz,
                                                                   jint dev_id, jint width,
                                                                   jint height) {
  LOG_INFO("fun:%s devID:%d,width:%d,height:%d", __FUNCTION__, dev_id, width, height)
  UserAgent::Instance()->modifyCameraDevice(dev_id, width, height);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_fan_play_media_engine_MediaEngine_ModifyAudioDevice(JNIEnv *env, jobject thiz,
                                                             jint sample_rate, jint channel_num,
                                                             jint samples_bit_per) {
  LOG_INFO("fun:%s sampleRate:%d,channelNum:%d,samplesBitPer:%d", __FUNCTION__, sample_rate,
           channel_num, samples_bit_per)
  UserAgent::Instance()->modifyAudioDevice(sample_rate, channel_num, samples_bit_per);
}

extern "C"
JNIEXPORT jobject JNICALL
Java_com_fan_play_media_engine_MediaEngine_FindCaptureDevice(JNIEnv *env, jobject thiz,
                                                             jint dev_id) {
  LOG_INFO("fun:%s devID:%d", __FUNCTION__, dev_id)
  auto pDevice = UserAgent::Instance()->findCaptureDevice(dev_id);
  Convert_Device deviceConvert;
  return deviceConvert.object2Java(pDevice);
}

extern "C"
JNIEXPORT jobject JNICALL
Java_com_fan_play_media_engine_MediaEngine_GetCaptureDevice(JNIEnv *env, jobject thiz) {
  LOG_INFO("fun:%s", __FUNCTION__)
  auto devList = UserAgent::Instance()->getCaptureDevice();
  Convert_Device deviceConvert;
  return deviceConvert.objectList2JavaList(devList);
}

extern "C"
JNIEXPORT jint JNICALL
Java_com_fan_play_media_engine_MediaEngine_GetCameraDeviceNum(JNIEnv *env, jobject thiz) {
  LOG_INFO("fun:%s", __FUNCTION__)
  return UserAgent::Instance()->getCameraDeviceNum();
}

extern "C"
JNIEXPORT void JNICALL
Java_com_fan_play_media_engine_MediaEngine_RegisterCaptureDeviceListener(JNIEnv *env, jobject thiz,
                                                                         jobject listener) {
  // TODO: implement RegisterCaptureDeviceListener()
}

extern "C"
JNIEXPORT jboolean JNICALL
Java_com_fan_play_media_engine_MediaEngine_StartCapture(JNIEnv *env, jobject thiz, jint dev_id) {
  // TODO: implement StartCapture()
}

extern "C"
JNIEXPORT void JNICALL
Java_com_fan_play_media_engine_MediaEngine_StopCapture(JNIEnv *env, jobject thiz, jint dev_id) {
  // TODO: implement StopCapture()
}

extern "C"
JNIEXPORT void JNICALL
Java_com_fan_play_media_engine_MediaEngine_StartPreview(JNIEnv *env, jobject thiz, jint dev_id,
                                                        jobject surface) {
  // TODO: implement StartPreview()
}

extern "C"
JNIEXPORT void JNICALL
Java_com_fan_play_media_engine_MediaEngine_StopPreview(JNIEnv *env, jobject thiz, jint dev_id) {
  // TODO: implement StopPreview()
}

extern "C"
JNIEXPORT void JNICALL
Java_com_fan_play_media_engine_MediaEngine_StartRecord(JNIEnv *env, jobject thiz, jint dev_id,
                                                       jstring save_path) {
  // TODO: implement StartRecord()
}

extern "C"
JNIEXPORT void JNICALL
Java_com_fan_play_media_engine_MediaEngine_StopRecord(JNIEnv *env, jobject thiz, jint dev_id) {
  // TODO: implement StopRecord()
}

extern "C"
JNIEXPORT void JNICALL
Java_com_fan_play_media_engine_MediaEngine_ResumeRecord(JNIEnv *env, jobject thiz, jint dev_id) {
  // TODO: implement ResumeRecord()
}

extern "C"
JNIEXPORT void JNICALL
Java_com_fan_play_media_engine_MediaEngine_PauseRecord(JNIEnv *env, jobject thiz, jint dev_id) {
  // TODO: implement PauseRecord()
}

extern "C"
JNIEXPORT void JNICALL
Java_com_fan_play_media_engine_MediaEngine_StartPush(JNIEnv *env, jobject thiz, jint dev_id,
                                                     jstring push_url) {
  // TODO: implement StartPush()
}

extern "C"
JNIEXPORT void JNICALL
Java_com_fan_play_media_engine_MediaEngine_StopPush(JNIEnv *env, jobject thiz, jint dev_id) {
  // TODO: implement StopPush()
}
